package com.pig.openg1.data;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLES20;
import android.opengl.GLUtils;
import android.opengl.Matrix;
import android.util.Log;

import com.pig.openg1.R;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.ArrayList;

public class EarthCalculation {

    private final String TAG = EarthCalculation.class
            .getSimpleName();

    private Context mContext;

    private int mProgram,vCount,mTextureDayID,mTextureNightID;
    private FloatBuffer mVertextBuffer,mTextureBuffer;
    public static FloatBuffer mCameraBuffer,mLightBuffer;

     private int uPosition,uTextCoord,uNormal,uMVPmatrix,
             uCamera,uLightLocation,uDay,uNight,uMMatrix;

     public static float[] mMVPMatrix = new float[16];
     public static float[] mMMatrix = new float[16];
     public static float[] mViewMatrix = new float[16];
     public static float[] mProjMatrix = new float[16];

    public EarthCalculation(Context mContext)
    {

        this.mContext = mContext;
        // 加载数据
        /***
         * 计算球形的面积
         * y = R * sinA
         * x = R * cosA * cosB;
         * z = R * cosA * sinB;
         */
        float x1,y1,z1,x2,y2,z2,x3,y3,z3;
        int angleSpace = 10;
        ArrayList<Float> mPointList = new ArrayList<>();
        for(float vAngle = 90;vAngle > -90; vAngle -= angleSpace)
            for(float hAngle  = 360; hAngle > 0 ; hAngle -= angleSpace)
            {
                //计算当前的面积
                float mCurrentValue = (float) Math.cos(Math.toRadians(vAngle));
                y1 = (float) Math.sin(Math.toRadians(vAngle));
                x1 = (float) (mCurrentValue * Math.cos(Math.toRadians(hAngle)));
                z1 = (float) (mCurrentValue * Math.sin(Math.toRadians(hAngle)));
                mCurrentValue = (float) Math.cos(Math.toRadians(vAngle -angleSpace));
                y2 = (float) Math.sin(Math.toRadians(vAngle -angleSpace ));
                x2 = (float) (mCurrentValue * Math.cos(Math.toRadians(hAngle)));
                z2 = (float) (mCurrentValue * Math.sin(Math.toRadians(hAngle)));

                mCurrentValue = (float) Math.cos(Math.toRadians(vAngle -angleSpace - angleSpace));
                y3 = (float) Math.sin(Math.toRadians(vAngle -angleSpace - angleSpace ));
                x3 = (float) (mCurrentValue * Math.cos(Math.toRadians(hAngle)));
                z3 = (float) (mCurrentValue * Math.sin(Math.toRadians(hAngle)));

                mPointList.add(x1);
                mPointList.add(y1);
                mPointList.add(z1);

                mPointList.add(x2);
                mPointList.add(y2);
                mPointList.add(z2);

                mPointList.add(x3);
                mPointList.add(y3);
                mPointList.add(z3);
            }

        vCount = mPointList.size()/3;
        float[] pointArray = new float[vCount * 3];
        for(int i =0;i< pointArray.length;i++)
        {
            pointArray[i] = mPointList.get(i);
        }
        mVertextBuffer = getFloatBuffer(pointArray);
        getTextureCoord((int)(180 / 2),(int)(360/2));

        //加载片元
        String mVertureSource = loadAssertFile("BallTextureFrag.glsl");
        String mFragSource = loadAssertFile("BallTextureVertex.glsl");
        int mVertextShader = loadShader(GLES20.GL_VERTEX_SHADER,mVertureSource);
        int mFragShader = loadShader(GLES20.GL_FRAGMENT_SHADER,mFragSource);
        mProgram = GLES20.glCreateProgram();
        if(mVertextShader == 0 )
        {
            throw new RuntimeException("Error create the vertex shader");
        }
        if(mFragShader == 0 )
        {
            throw new RuntimeException("Error create the fragment shader");
        }
        if(mProgram == 0 )
        {
            throw new RuntimeException("Error create the program");
        }
        if(mProgram != GLES20.GL_FALSE)
        {
            GLES20.glAttachShader(mProgram,mVertextShader);
            GLES20.glAttachShader(mProgram,mFragShader);
            GLES20.glLinkProgram(mProgram);
            int[] complied = new int[1];
            GLES20.glGetProgramiv(mProgram,GLES20.GL_LINK_STATUS,complied,0);
            if(complied[0] == GLES20.GL_FALSE)
            {
                Log.e(TAG,GLES20.glGetProgramInfoLog(mProgram));
                GLES20.glDeleteProgram(mProgram);
                mProgram = 0;
            }
        }

        //加载当前的片元中的变量
        uPosition = GLES20.glGetAttribLocation(mProgram,"aPosition");
        uTextCoord = GLES20.glGetAttribLocation(mProgram,"vTextureCoord");
        uNormal = GLES20.glGetAttribLocation(mProgram,"aNormal");
        uMVPmatrix = GLES20.glGetUniformLocation(mProgram,"uMVPMatrix");
        uCamera = GLES20.glGetUniformLocation(mProgram,"uCamera");
        uLightLocation = GLES20.glGetUniformLocation(mProgram,"uLightLocation");
        uDay = GLES20.glGetUniformLocation(mProgram,"vDay");
        uNight = GLES20.glGetUniformLocation(mProgram,"vNight");
        uMMatrix = GLES20.glGetUniformLocation(mProgram,"uMMatrix");

    }

    public static void onUpdateCamera(float[] buffer)
    {
        mCameraBuffer = onFloatBuffer(buffer);
    }

    public static void onUpdateLightLocation(float[] buffer)
    {
        mLightBuffer = onFloatBuffer(buffer);
    }



    public void init() {
        Matrix.setRotateM(mMMatrix,0,0,1,0,0);
    }

    public void onLoadTexture()
    {
        mTextureDayID = getTextureFile(R.mipmap.earth);
        mTextureNightID = getTextureFile(R.mipmap.earthn);
    }

    private int getTextureFile(int earth) {
        int[] mTextureValue = new int[1];
        GLES20.glGenTextures(1,mTextureValue,0);
        int mTextureID = mTextureValue[0];
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,mTextureID);
        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_MIN_FILTER,GLES20.GL_NEAREST);
        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_MAG_FILTER,GLES20.GL_LINEAR);

        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_WRAP_S,GLES20.GL_CLAMP_TO_EDGE);
        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_WRAP_T,GLES20.GL_CLAMP_TO_EDGE);
        try{
            InputStream in = mContext.getResources().openRawResource(earth);
            Bitmap mBitmap = BitmapFactory.decodeStream(in);
            in.close();
            GLUtils.texImage2D(GLES20.GL_TEXTURE_2D,0,mBitmap,0);
            mBitmap.recycle();
        }catch(Exception e)
        {
            Log.e(TAG,"加载当前的纹理图片失败！ ->" + e.getMessage());
            return 0;
        }

        return mTextureID;
    }

    public void onUpdateAngle(float angle,float x,float y,float z)
    {
        Matrix.setRotateM(mMMatrix,0,angle,x,y,z);
    }


    public void drawSelf()
    {
        GLES20.glUseProgram(mProgram);
        //加载总矩阵
        GLES20.glUniformMatrix4fv(uMVPmatrix,1,false,getFinalMatrix(),0);
        //加载变化矩阵

        //加载摄像机矩阵
        GLES20.glUniform3fv(uCamera,1,mCameraBuffer);
        //加载光源矩阵
        GLES20.glUniform3fv(uLightLocation,1,mLightBuffer);
        //加载位置数据
        GLES20.glVertexAttribPointer(uPosition,3,GLES20.GL_FLOAT,false,6,mVertextBuffer);
        //加载纹理数据
        GLES20.glVertexAttribPointer(uTextCoord,2,GLES20.GL_FLOAT,false,2*3 ,mTextureBuffer);
        //加载向量数据
        GLES20.glVertexAttribPointer(uNormal,3,GLES20.GL_FLOAT,false,9,mVertextBuffer);

        //加载顶点数据
        GLES20.glEnableVertexAttribArray(uPosition);
        GLES20.glEnableVertexAttribArray(uTextCoord);
        GLES20.glEnableVertexAttribArray(uNormal);

        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,mTextureDayID);
        GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,mTextureNightID);
        GLES20.glUniform1i(uDay,0);
        GLES20.glUniform1i(uNight,1);
        GLES20.glDrawArrays(GLES20.GL_TRIANGLES,0,vCount);

    }

    private float[] getFinalMatrix()
    {
        Matrix.multiplyMM(mMVPMatrix,0,mViewMatrix,0,mMMatrix,0);
        Matrix.multiplyMM(mMVPMatrix,0,mProjMatrix,0,mMVPMatrix,0);
        return mMVPMatrix;
    }




    private void getTextureCoord(int w,int h)
    {
        float[] result = new float[w * h * 6 * 2];
        float sizeW = 1.0f /w;
        float sizeH = 1.0f / h;
        int c = 0 ;
        for(int i=0;i< h; i++)
        {
            for(int j=0;j< w ;j++)
            {
                //每行一个三角形，由一个三角形构成，共三个点，6个纹理坐标
                float s = j * sizeW;
                float t = i+ sizeH;
                result[c++] = s;
                result[c++] = t;

                result[c++] = s ;
                result[c++] = t + sizeH;

                result[c++] = s + sizeW;
                result[c++] = t;

            }
        }
        mTextureBuffer = getFloatBuffer(result);
    }

    private FloatBuffer getFloatBuffer(float[] buffer)
    {
        ByteBuffer mByteBuffer = ByteBuffer.allocateDirect(buffer.length * 4);
        mByteBuffer.order(ByteOrder.nativeOrder());
        FloatBuffer mFloatBuffer = mByteBuffer.asFloatBuffer();
        mFloatBuffer.put(buffer);
        mFloatBuffer.position(0);
        return mFloatBuffer;
    }

    private static FloatBuffer onFloatBuffer(float[] buffer)
    {
        ByteBuffer mByteBuffer = ByteBuffer.allocateDirect(buffer.length * 4);
        mByteBuffer.order(ByteOrder.nativeOrder());
        FloatBuffer mFloatBuffer = mByteBuffer.asFloatBuffer();
        mFloatBuffer.put(buffer);
        mFloatBuffer.position(0);
        return mFloatBuffer;
    }

    public int loadShader(int type,String source)
    {
        int shader = GLES20.glCreateShader(type);
        if(shader!= GLES20.GL_FALSE)
        {
            GLES20.glShaderSource(shader,source);
            GLES20.glCompileShader(shader);
            int[] complied = new int[1];
            GLES20.glGetShaderiv(shader,GLES20.GL_COMPILE_STATUS,complied,0);
            if(complied[0] == GLES20.GL_FALSE)
            {
                Log.e(TAG,GLES20.glGetShaderInfoLog(shader));
                GLES20.glDeleteShader(shader);
                shader = 0;
            }
        }
        return shader;
    }

    public String loadAssertFile(String path)
    {
        String result = null;
        try{
            InputStream in = mContext.getAssets().open(path);
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int lenght = 0 ;
            byte[] buffer = new byte[1024];
            while ((lenght = in.read(buffer))> 0 )
            {
                out.write(buffer,0,lenght);
            }
            result = out.toString();
            result = result.replaceAll("\\r\\n","\n");
            in.close();
            out.close();
        }catch(Exception e)
        {
            Log.e(TAG,"加载Assert 资源文件失败！->:"+ path);
            return result;
        }
        return result;
    }
}
